﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.IO;
using CodeSample.Model;
using CodeSample.Utils;

namespace CodeSample
{
    enum EditMode { Insert, Update }
    /// <summary>
    /// Interaction logic for InsertUpdateWindow.xaml
    /// </summary>
    public partial class InsertUpdateWindow : Window
    {
        private string Id = "";
        private RTFEditor editor;
        private EditMode editMode;
        public delegate void InsertUpdateCallBackDelegate(string affectedSampleID, string statusMessage);
        InsertUpdateCallBackDelegate insertUpdateCallBack;
        DataProcessMan dataProcess;
        private bool isSampleEdited = false;

        public InsertUpdateWindow(InsertUpdateCallBackDelegate insertUpdateCallBack, DataProcessMan dataProcess)
        {
            InitializeComponent();

            this.editMode = EditMode.Insert;
            this.editor = new RTFEditor();
            this.txtAuthor.Text = Environment.MachineName;
            this.rchtxtCode.Document.Blocks.FirstBlock.LineHeight = 3;
            this.insertUpdateCallBack = insertUpdateCallBack;
            this.dataProcess = dataProcess;

            this.txtAuthor.TextChanged += this.txt_TextChanged;
            this.txtDetails.TextChanged += this.txt_TextChanged;
            this.txtLanguage.TextChanged += this.txt_TextChanged;
            this.txtName.TextChanged += this.txt_TextChanged;
            this.txtPurpose.TextChanged += this.txt_TextChanged;
            this.rchtxtCode.TextChanged += this.txt_TextChanged;
        }

        public InsertUpdateWindow(SampleMan aSample, InsertUpdateCallBackDelegate insertUpdateCallBack, DataProcessMan dataProcess)
        {
            InitializeComponent();

            this.editMode = EditMode.Update;
            this.editor = new RTFEditor();
            this.rchtxtCode.Document.Blocks.FirstBlock.LineHeight = 3;
            //aSample = new CodeSample.Sample("Java", "Insert database",
            //    @"{\rtf1\ansi\ansicpg1252\uc1\htmautsp\deff2{\fonttbl{\f0\fcharset0 Times New Roman;}{\f2\fcharset0 Lucida Sans Unicode;}{\f3\fcharset0 Consolas;}}{\colortbl\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red43\green145\blue175;\red163\green21\blue21;}\loch\hich\dbch\pard\plain\ltrpar\itap0{\lang1033\fs19\f3\cf0 \cf0\ql{\f3 {\ltrch         }{\cf2\ltrch private}{\ltrch  }{\cf2\ltrch void}{\ltrch  rchtxtCode_TextChanged(}{\cf2\ltrch object}{\ltrch  sender, }{\cf3\ltrch TextChangedEventArgs}{\ltrch  e)}\li0\ri0\sa0\sb0\fi0\ql\par}{\f3 {\ltrch         \{}\li0\ri0\sa0\sb0\fi0\ql\par}{\f3 {\ltrch             }{\cf2\ltrch string}{\ltrch  text = }{\cf2\ltrch this}{\ltrch .GetText(}{\cf2\ltrch this}{\ltrch .rchtxtCode);}\li0\ri0\sa0\sb0\fi0\ql\par}{\f3 {\ltrch             }{\cf2\ltrch string}{\ltrch [] textArray = text.Split(}{\cf4\ltrch '\\n'}{\ltrch );}\li0\ri0\sa0\sb0\fi0\ql\par}{\f3 {\ltrch             }{\cf2\ltrch string}{\ltrch  rtfText = }{\cf2\ltrch this}{\ltrch .GetRTFText(}{\cf2\ltrch this}{\ltrch .rchtxtCode);}\li0\ri0\sa0\sb0\fi0\ql\par}{\f3 {\ltrch         \}}\li0\ri0\sa0\sb0\fi0\ql\par}}}",
            //    new CodeSample.SampleDescription("Hiep", "Dùng để insert vào database", "coi chừng chương trình bị đứng lskdfjơ óidfơie lksjdfi sldkfjiws lksjdfi lksdjfiqư lksfdjiwoe"));

            this.Id = aSample.Id;
            this.txtLanguage.Text = aSample.Language;
            this.txtName.Text = aSample.Name;
            this.txtPurpose.Text = aSample.Description.Purpose;
            this.txtDetails.Text = aSample.Description.Details;
            this.txtAuthor.Text = aSample.Description.Author;

            this.rchtxtCode.SelectAll();
            this.rchtxtCode.Selection.Load(
                new MemoryStream(ASCIIEncoding.Default.GetBytes(aSample.Code)), 
                DataFormats.Rtf);

            this.insertUpdateCallBack = insertUpdateCallBack;
            this.dataProcess = dataProcess;

            this.txtAuthor.TextChanged += this.txt_TextChanged;
            this.txtDetails.TextChanged += this.txt_TextChanged;
            this.txtLanguage.TextChanged += this.txt_TextChanged;
            this.txtName.TextChanged += this.txt_TextChanged;
            this.txtPurpose.TextChanged += this.txt_TextChanged;
            this.rchtxtCode.TextChanged += this.txt_TextChanged;
        }

        private void rchtxtCode_SelectionChanged(object sender, RoutedEventArgs e)
        {
            string selectedPlainText = this.rchtxtCode.Selection.Text;
            if (selectedPlainText.Trim() == "" || !selectedPlainText.Contains("\r\n"))
            {
                this.btnFormat.IsEnabled = false;
                return;
            }

            string RTFText = this.GetRTFText(this.rchtxtCode,
                this.rchtxtCode.Selection.Start, this.rchtxtCode.Selection.End);

            if (editor.IsSpaceFormatNeeded(RTFText))
            {
                this.btnFormat.IsEnabled = true;
            }
            else
            {
                if (editor.IsTabFormatNeeded(RTFText))
                    this.btnFormat.IsEnabled = true;
                else
                    this.btnFormat.IsEnabled = false;
            }
        }

        private string GetText(RichTextBox richTextBox)
        {
            // use a TextRange to fish out the Text from the Document
            TextRange textRange = new TextRange(richTextBox.Document.ContentStart, richTextBox.Document.ContentEnd);
            return textRange.Text;
        }

        private string GetRTFText(RichTextBox richTextBox, TextPointer Start, TextPointer End)
        {
            TextRange tr = new TextRange(Start, End);
            MemoryStream ms = new MemoryStream();
            tr.Save(ms, DataFormats.Rtf);
            return ASCIIEncoding.Default.GetString(ms.ToArray());
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            if (this.isSampleEdited)
            {
                if (!this.Validate(true))
                    return;
                this.Save();
            }

            this.isSampleEdited = false;
            this.Close();
        }

        private void Save()
        {
            this.FormatData();

            string affectedSampleID;
            if (this.editMode == EditMode.Insert)
            {
                SampleMan aSample = new SampleMan(this.txtLanguage.Text,
                    this.txtName.Text, this.GetRTFText(this.rchtxtCode,
                    this.rchtxtCode.Document.ContentStart, this.rchtxtCode.Document.ContentEnd),
                    new SampleDescription(this.txtAuthor.Text, this.txtPurpose.Text, this.txtDetails.Text));
                affectedSampleID = dataProcess.AddNewSample(aSample, true);
                this.insertUpdateCallBack(affectedSampleID, "Insert successful");
            }
            else
            {
                SampleMan aSample = new SampleMan(this.Id, this.txtLanguage.Text,
                    this.txtName.Text, this.GetRTFText(this.rchtxtCode,
                    this.rchtxtCode.Document.ContentStart, this.rchtxtCode.Document.ContentEnd),
                    new SampleDescription(this.txtAuthor.Text, this.txtPurpose.Text, this.txtDetails.Text));
                affectedSampleID = dataProcess.UpdateSample(aSample);
                this.insertUpdateCallBack(affectedSampleID, "Update successful");
            }

        }

        private bool Validate(bool showMessage)
        { 
            this.rchtxtCode.SelectAll();

            if (this.txtLanguage.Text.Trim() == "")
            {
                if (showMessage)
                    MessageBox.Show("Language cannot be blank!", "Value missing", MessageBoxButton.OK, MessageBoxImage.Error);
                this.txtLanguage.Focus();
                return false;
            }
            if (this.txtName.Text.Trim() == "")
            {
                if (showMessage)
                    MessageBox.Show("Code Name cannot be blank!", "Value missing", MessageBoxButton.OK, MessageBoxImage.Error);
                this.txtName.Focus();
                return false;
            }
            if (this.rchtxtCode.Selection.Text.Trim() == "")
            {
                if (showMessage)
                    MessageBox.Show("Code cannot be blank!", "Value missing", MessageBoxButton.OK, MessageBoxImage.Error);
                this.rchtxtCode.Focus();
                return false;
            }
            if (this.txtPurpose.Text.Trim() == "")
            {
                if (showMessage)
                    MessageBox.Show("'What Code Do' text box cannot be blank!", "Value missing", MessageBoxButton.OK, MessageBoxImage.Error);
                this.txtPurpose.Focus();
                return false;
            }
            if (this.txtAuthor.Text.Trim() == "")
            {
                if (showMessage)
                    MessageBox.Show("Author cannot be blank!", "Value missing", MessageBoxButton.OK, MessageBoxImage.Error);
                this.txtAuthor.Focus();
                return false;
            }

            return true;
        }

        private void FormatData()
        {
            this.txtLanguage.Text = this.txtLanguage.Text.Trim();
            this.txtName.Text = this.txtName.Text.Trim();

            string UppercaseLanguage = this.txtLanguage.Text.ToUpper();
            if (UppercaseLanguage.Contains("HTML") ||
                UppercaseLanguage.Contains("CSS") ||
                UppercaseLanguage.Contains(".NET") ||
                UppercaseLanguage.Equals("AJAX") ||
                UppercaseLanguage.Equals("JSON") ||
                UppercaseLanguage.Equals("XML") ||
                UppercaseLanguage.Equals("XAML") ||
                UppercaseLanguage.Equals("SQL") ||
                UppercaseLanguage.Equals("ASP") ||
                UppercaseLanguage.Equals("PHP") ||
                UppercaseLanguage.Equals("JSP") ||
                UppercaseLanguage.Equals("RSS"))
                this.txtLanguage.Text = UppercaseLanguage;

            if (UppercaseLanguage.Equals("VBSCRIPT"))
                this.txtLanguage.Text = "VBScript";
            else if (UppercaseLanguage.Equals("JQUERY"))
                this.txtLanguage.Text = "jQuery";
            else if (UppercaseLanguage.Equals("JAVASCRIPT"))
                this.txtLanguage.Text = "JavaScript";
            else
                this.txtLanguage.Text = this.txtLanguage.Text.ToUpper()[0].ToString() + this.txtLanguage.Text.Substring(1);

            this.txtName.Text = this.txtName.Text.ToUpper()[0].ToString() + this.txtName.Text.Substring(1);
        }

        private void btnFormat_Click(object sender, RoutedEventArgs e)
        {
            string newRTFText;
            newRTFText = this.editor.RemoveLeadingSentenceTab(this.GetRTFText(this.rchtxtCode,
                this.rchtxtCode.Selection.Start, this.rchtxtCode.Selection.End));
            this.rchtxtCode.Selection.Load(new MemoryStream(ASCIIEncoding.Default.GetBytes(newRTFText)), DataFormats.Rtf);
            newRTFText = this.editor.RemoveLeadingSentenceSpace(this.GetRTFText(this.rchtxtCode,
                this.rchtxtCode.Selection.Start, this.rchtxtCode.Selection.End));
            this.rchtxtCode.Selection.Load(new MemoryStream(ASCIIEncoding.Default.GetBytes(newRTFText)), DataFormats.Rtf);

            this.btnFormat.IsEnabled = false;
            this.rchtxtCode.Focus();
        }

        private void txt_TextChanged(object sender, TextChangedEventArgs e)
        {
            this.isSampleEdited = true;
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (this.isSampleEdited)
            {
                if (MessageBox.Show("Do you want to save change?", "Save Change", 
                    MessageBoxButton.YesNo, MessageBoxImage.Warning) == MessageBoxResult.Yes)
                {
                    if (this.Validate(true))
                        this.Save();
                    else
                        e.Cancel = true;
                }
            }
        }

        private void Window_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Escape)
                this.Close();
        }
    }
}
